/*	JSWaterfall v0.1 <http://code.google.com/p/js-class-sugar/> 
	is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 
*/

/**
 * @author tonylua@sina.com
 * @sample
 * var _layout1 = new JSWaterfall({
 * 	container: 'listContainer1', //列表容器
 * 	width: 978, //总宽度
 * 	colNum: 4, //列数
 * 	colGap: 10, //列间隔
 * 	itemClass: 'itemBox', //单个项目样式类
 * 	itemWrapper: '<div class="iBkT"><div class="iBkB"></div></div>' //单个项目的内层包装（可选）
 * });	
 * 	
 * _layout1.render();
 * _layout1.addDoms(['#st_weibo', '#st_lbs_none'], true, 3); //添加已存在的dom，到列尾，在第4列
 * _layout1.addData(['xxx','frfg3g']); //添加字符串内容的元素，后两个可选参数和addDoms一致
 */

var JSWaterfall = (function(){		
	var Const;
	/**
	 * 构造方法
	 * @constuctor
	 * @param Object config 配置
	 * @return JSWaterfall
	 */
	Const = function(config){
		if (!window.jQuery)
			throw "[JSWaterfall] jQuery not found!";
		if (!document.getElementById(config.container))
			throw "container ID error!";
			
		this._cfg = config;
		this._data = [];
		this._cols = [];
		this._addFlag = -1;
		return this;
	};
	Const.prototype = {
		/**
		 * 开始渲染
		 * @public
		 * @return JSWaterfall
		 */
		render: function(){
			this._init();
			return this;
		},
		/**
		 * 添加dom数据
		 * @public
		 * @param Array|String contextArray 目标dom上下文的集合
		 * @param Boolean isAppend 加到最后还是最前
		 * @param uint colIdx 可选, 指定添加到的列
		 * @return JSWaterfall
		 */
		addDoms: function(contextArray, isAppend, colIdx){
			
			if (typeof isAppend == 'undefined')
				isAppend = true;
			
			var data = contextArray;
			if ( !(data instanceof Array) ) 
				data = [data];
			this._data = this._data.concat(data);
			
			var i=1,
				lng = data.length,
				$collect = $(data[0]);
			for (;i<lng;i++)
				$collect = $collect.add( $(data[i]) );
			data = $.makeArray($collect);
			$collect = null;
			
			this._addFlag += 1;
			
			i = 0;
			lng = data.length;
			if (typeof colIdx != 'undefined')
				for (;i<lng;i++)
					if (isAppend)
						this._cols[colIdx].append( this._wrapItem(data[i], this._addFlag, i, 1) );
					else
						this._cols[colIdx].prepend( this._wrapItem(data[i], this._addFlag, i, 1) );
			else
				for (;i<lng;i++)
					if (isAppend)
						this._getShortCol().append( this._wrapItem(data[i], this._addFlag, i, 1) );
					else
						this._getShortCol().prepend( this._wrapItem(data[i], this._addFlag, i, 1) );
			
			this.renderHeight();
			
			return this;
		},
		/**
		 * 添加string数据
		 * @public
		 * @param Array|String data 填充内容的集合
		 * @param Boolean isAppend 加到最后还是最前
		 * @param uint colIdx 可选, 指定添加到的列
		 * @return JSWaterfall
		 */
		addData: function(data, isAppend, colIdx){
			
			if (typeof isAppend == 'undefined')
				isAppend = true;
			
			if ( !(data instanceof Array) ) 
				data = [data];
			this._data = this._data.concat(data);
			
			this._addFlag += 1;
			
			var i = 0,
				lng = data.length;
			if (typeof colIdx != 'undefined')
				for (;i<lng;i++)
					if (isAppend)
						this._cols[colIdx].append( this._wrapItem(data[i], this._addFlag, i) );
					else
						this._cols[colIdx].prepend( this._wrapItem(data[i], this._addFlag, i) );
			else
				for (;i<lng;i++)
					if (isAppend)
						this._getShortCol().append( this._wrapItem(data[i], this._addFlag, i) );
					else
						this._getShortCol().prepend( this._wrapItem(data[i], this._addFlag, i) );
			
			this.renderHeight();
			
			return this;
		},
		/**
		 * 数据发生变化时确保高度正常
		 * @public
		 * @return JSWaterfall
		 */
		renderHeight: function(){
			$('#'+this._cfg.container).height( this._getLongCol().height() + 'px' );
			
			return this;
		},
		/**
		 * 取得列的集合
		 * @public
		 * @return Array
		 */
		getCols: function(){
			return this._cols;
		},
		/**
		 * 取得所有数据
		 * @public
		 * @return Array
		 */
		getData: function(){
			return this._data;
		},
		
		_getColsSort: function(){
			var i = 0,
				wArr = [];
			for (;i<this._cfg.colNum;i++)
				wArr.push({ idx:i, w:this._cols[i].height() });
			wArr.sort(function(a,b){return a.w-b.w;});
			return wArr;
		},
		_getShortCol: function(){
			var wArr = this._getColsSort();
			return this._cols[wArr[0].idx];
		},
		_getLongCol: function(){
			var wArr = this._getColsSort();
			return this._cols[wArr[wArr.length-1].idx];
		},
		_wrapItem: function(data, addflag, idx, type){
			if (typeof type == 'undefined')
				type = 0;
			
			var rtn = null,
				liStr = '<li class="'+this._cfg.itemClass+'" rel="'+addflag+'-'+idx+'"></li>';
			if (type == 0){ //处理string内容
				var $li = $(liStr);
				if (this._cfg.itemWrapper){
					var $wr = $(this._cfg.itemWrapper),
						$inner = $wr;
					while ($inner.children().length)
						$inner = $inner.children();
					$inner.html(data);
					$li.append($wr);
					$wr = null;
				}else{
					$li.html(data);
				}
				rtn = $li;					
			}else if (type == 1){ //处理dom内容					
				var $d = $(data);
				$d.wrap(liStr);
				if (this._cfg.itemWrapper){
					$d.wrap(this._cfg.itemWrapper);
				}
				rtn = $d.parents('li.'+this._cfg.itemClass).eq(0);					
			}				
			return rtn;
		},
		_init: function(){
			//建立基本结构
			var chtml = ['<div class="jsfCompCtn"><div class="jsfCompInner">'],
				w = Math.floor( (this._cfg.width-(this._cfg.colNum-1)*this._cfg.colGap)/this._cfg.colNum ),
				i = 0,
				$ctn = $('#'+this._cfg.container);
			for (;i<this._cfg.colNum;i++)
				chtml.push('<ul class="jsfCompCol" rel="'+i+'"></ul>');
			chtml.push('</div></div>');
			$ctn.html(chtml.join(''));
			$ctn.find('.jsfCompCtn').css({
				width: this._cfg.width*1 + 'px',
				overflow: 'hidden'
			});
			$ctn.find('.jsfCompInner').css({
				width: (this._cfg.width*1+this._cfg.colGap*1+5) + 'px'
			});
			for (i=0;i<this._cfg.colNum;i++){
				this._cols[i] = $ctn.find('.jsfCompInner > ul').eq(i);
				this._cols[i].css({
					width: w+'px',
					overflow: 'hidden',
					display: 'inline-block',
					'float': 'left',
					paddingTop: '1px', //防止无内容时宽度错误
					marginRight: this._cfg.colGap+'px'
				});
			}
		}
	};
	return Const;
}());